#include "st7735s.h"
#include "font.h"
#include "delay.h" //使用延时函数

#define W 128
#define H 160
#define WxH 20480
#define FONT font1608

struct ST7735_cmdBuf
{
    uint8_t command;  //命令
    uint8_t delay;    //延时
    uint8_t len;      //参数长度
    uint8_t data[16]; //参数字节
};

uint16_t Color = 0x00f0;
uint16_t Sbuf[WxH] = {0};

#if 0
static const struct ST7735_cmdBuf initializers[] = {
    //SWRESET Software reset
    {0x01, 150, 0, 0},
    //SLPOUT Sleep Out and Booster on
    {0x11, 150, 0, 0},
    //FRMCTR1、FRMCTR2   In Normal Mode, idle
    {0XB1, 0, 3, {0X01, 0X2C, 0x2D}},
    {0XB2, 0, 3, {0X01, 0X2C, 0x2D}},
    //FRMCTR3 Frame rate configuretion --partial mode
    {0xB3, 0, 6, {0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D}},
    //INVCTR Display Inversion Control  ---no inversion
    {0xB4, 0, 1, {0x07}},
    //PWCTR1 Power Control Setting   ---4.6V Auto mode
    {0xC0, 0, 3, {0xA2, 0x02, 0x84}},
    //PWCTR2 Power Control Setting   ---VGH25 2.4C, VGSEL -10, VGH = 3 * AVDD
    {0xC1, 0, 1, {0xC5}},
    //PWCTR3 Power Control Setting   ---opamp current smal, boost frequency
    {0xC2, 0, 2, {0x0A, 0x00}},
    //PWCTR4 Power Control Setting   ---BLK/2, opamp current small and medium low
    {0xC3, 0, 2, {0x8A, 0x2A}},
    //PWCTR5 Power Control Setting   ---
    {0xC4, 0, 2, {0x8A, 0xEE}},
    //VMCTR1 VCOM Control1
    {0xC5, 0, 1, {0x0E}},
    //INVOFF Don't Invert display
    {0x20, 0, 0 , 0},
    //Memory access directions, row address/col address, bottom to top refesh(10.1.27)
    {0x36, 0, 1, {0x00}},
    //Color mode set 16bit 10.1.30
    {0x3a, 0, 1,{0x05}},
    //Column address set 
    {0x2a, 0, 4, {0x00, 0x00, 0x00, 0x7F}},
    //Row address set
    {0x2b, 0, 4, {0x00, 0x00, 0x00, 0x9F}},
    //GMCTRP2 Gamma Polarity corrction
    {0xE0, 0, 16, { 0x02, 0x1C, 0x07, 0x12,
                    0x37, 0x32, 0x29, 0x2D,
                    0x29, 0x25, 0x2B, 0x39,
                    0x00, 0x01, 0x03, 0x10}},
    // GMCTRP2 Gamma Polarity corrction
    {0xE1, 0, 16, { 0x03, 0x1d, 0x07, 0x06,
                    0x2E, 0x2C, 0x29, 0x2D,
                    0x2E, 0x2E, 0x37, 0x3F,
                    0x00, 0x00, 0x02, 0x10}},
    //DISPON Display on 
    {0x29, 100, 0, 0},
    // NORON Normal on
    {0x13, 10, 0, 0},
    //End
    {0, 0, 0, 0}
};
#endif

/**
  * @brief  初始化液晶相关引脚
  *
  * @note   需要实现一个ST7735S_GPIO_INIT宏定义，它用来初始化液晶想相关引脚
  *         CS      配置为输出，控制液晶是否被选中
  *         DC      配置为输出，控制液晶命令和数据模式切换
  *         RESET   配置为输出，对液晶控制器复位
  *         BLK     配置为输出，液晶背光控制
  * 
  * @retval None
  */
static void ST7735S_GPIO_Init(void)
{
    // #ifdef ST7735S_GPIO_INIT
    //     ST7735S_GPIO_INIT;
    // #else
    // #error "需要定义LCD引脚初始化函数"
    // #endif

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();

    GPIO_InitStruct.Pin = ST7735S_CS_PIN | ST7735S_RESET_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(ST7735S_CS_PIN_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = ST7735S_DC_PIN | ST7735S_BLK_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(ST7735S_BLK_PIN_PORT, &GPIO_InitStruct);
}

/**
  * @brief  向st7735s发送命令
  *
  * @param  cmd：发送的命令
  * 
  * @retval None
  */
static void ST7735S_WriteCommand(uint8_t cmd)
{
    //片选线拉低
    ST7735S_CS_LOW;
    //方向控制，写模式
    ST7735S_DC_W;
    //发送数据
    SPI2_ReadWriteByte(cmd);
    //片选线拉高
    ST7735S_CS_HIGH;
}

/**
  * @brief  向st7735s发送数据
  *
  * @param  dat：发送的数据
  * 
  * @retval None
  */
static void ST7735S_WriteData(uint8_t dat)
{
    //片选线拉低
    ST7735S_CS_LOW;
    //方向控制，读模式
    ST7735S_DC_R;
    //发送数据
    SPI2_ReadWriteByte(dat);
    //片选线拉高
    ST7735S_CS_HIGH;
}

/**
  * @brief  向st7735s发送2字节数据
  *
  * @param  dat：发送的数据
  * 
  * @retval None
  */
static void ST7735S_WriteData_16Bit(uint16_t dat)
{
    //片选线拉低
    ST7735S_CS_LOW;
    //方向控制，读模式
    ST7735S_DC_R;
    //发送数据
    SPI2_ReadWriteByte(dat >> 8);
    SPI2_ReadWriteByte(dat & 0xFF);
    //片选线拉高
    ST7735S_CS_HIGH;
}

/**
  * @brief  复位st7735s
  * 
  * @retval None
  */
static void ST7735S_Reset(void)
{

    ST7735S_RESET_LOW;
    //延时
    Sys_Delay_ms(300);
    //不复位

    ST7735S_RESET_HIGH;
    //延时
    Sys_Delay_ms(100);
}

/**
  * @brief  打开液晶背光st7735s
  * 
  * @retval None
  */
void ST7735S_OpenBLK(void)
{
    //ST7735S_CS_LOW;
    ST7735S_BLK_HIGH;
    //ST7735S_CS_HIGH;
}

/**
  * @brief  关闭液晶背光st7735s
  * 
  * @retval None
  */
void ST7735S_CloseBLK(void)
{
    //ST7735S_CS_LOW;
    ST7735S_BLK_LOW;
    //ST7735S_CS_HIGH;
}

/**
  * @brief  液晶初始化
  * 
  * @retval None
  */
void ST7735S_Init(void)
{
    ST7735S_GPIO_Init();
    ST7735S_Reset();

    ST7735S_WriteCommand(0x11); //退出休眠
    Sys_Delay_ms(180);

    ST7735S_WriteCommand(0xB1);
    ST7735S_WriteData(0x01);
    ST7735S_WriteData(0x2C);
    ST7735S_WriteData(0x2D);
    ST7735S_WriteCommand(0xB2);
    ST7735S_WriteData(0x01);
    ST7735S_WriteData(0x2C);
    ST7735S_WriteData(0x2D);
    ST7735S_WriteCommand(0xB3);
    ST7735S_WriteData(0x01);
    ST7735S_WriteData(0x2C);
    ST7735S_WriteData(0x2D);
    ST7735S_WriteData(0x01);
    ST7735S_WriteData(0x2C);
    ST7735S_WriteData(0x2D);

    ST7735S_WriteCommand(0xB4); //不反转
    ST7735S_WriteData(0x07);

    ST7735S_WriteCommand(0xC0);
    ST7735S_WriteData(0xA2);
    ST7735S_WriteData(0x02);
    ST7735S_WriteData(0x84);

    ST7735S_WriteCommand(0xC1);
    ST7735S_WriteData(0xC5);

    ST7735S_WriteCommand(0xC2);
    ST7735S_WriteData(0x0A);
    ST7735S_WriteData(0x00);

    ST7735S_WriteCommand(0xC3);
    ST7735S_WriteData(0x8A);
    ST7735S_WriteData(0x2A);

    ST7735S_WriteCommand(0xC4);
    ST7735S_WriteData(0x8A);
    ST7735S_WriteData(0xEE);

    ST7735S_WriteCommand(0xC5);
    ST7735S_WriteData(0x0E);

    ST7735S_WriteCommand(0x36);
    ST7735S_WriteData(0xC0);

    ST7735S_WriteCommand(0xE0);
    ST7735S_WriteData(0x0F);
    ST7735S_WriteData(0x1A);
    ST7735S_WriteData(0x0F);
    ST7735S_WriteData(0x18);
    ST7735S_WriteData(0x2F);
    ST7735S_WriteData(0x28);
    ST7735S_WriteData(0x20);
    ST7735S_WriteData(0x22);
    ST7735S_WriteData(0x1F);
    ST7735S_WriteData(0x1B);
    ST7735S_WriteData(0x23);
    ST7735S_WriteData(0x37);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(0x07);
    ST7735S_WriteData(0x02);
    ST7735S_WriteData(0x10);

    ST7735S_WriteCommand(0xE1);
    ST7735S_WriteData(0x0F);
    ST7735S_WriteData(0x1B);
    ST7735S_WriteData(0x0F);
    ST7735S_WriteData(0x17);
    ST7735S_WriteData(0x33);
    ST7735S_WriteData(0x2C);
    ST7735S_WriteData(0x29);
    ST7735S_WriteData(0x2E);
    ST7735S_WriteData(0x30);
    ST7735S_WriteData(0x30);
    ST7735S_WriteData(0x39);
    ST7735S_WriteData(0x3F);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(0x07);
    ST7735S_WriteData(0x03);
    ST7735S_WriteData(0x10);

    ST7735S_WriteCommand(0x2A);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(0x7F);
    ST7735S_WriteCommand(0x2B);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(0x9F);

    //ST7735S_WriteCommand(0x13);
    //ST7735S_WriteData(0x00);

    ST7735S_WriteCommand(0xF0);
    ST7735S_WriteData(0x01);

    ST7735S_WriteCommand(0xF6);
    ST7735S_WriteData(0x00);

    ST7735S_WriteCommand(0x3A);
    ST7735S_WriteData(0x05);

    ST7735S_WriteCommand(0x29);
}

/**
  * @brief  设置st7735s地址
  * 
  * @retval None
  */
void ST7735S_SetAddressWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
    ST7735S_WriteCommand(0x2A);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(x0);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(x1 + 2);

    ST7735S_WriteCommand(0x2B);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(y0);
    ST7735S_WriteData(0x00);
    ST7735S_WriteData(y1 + 1);

    ST7735S_WriteCommand(0x2C);
}

static void ST7735S_SetXY(uint16_t x, uint16_t y)
{
    ST7735S_SetAddressWindow(x, y, x, y);
}

/**
  * @brief  画一个点
  * 
  * @retval None
  */
void ST7735S_DrawPoint(uint16_t x, uint16_t y, uint16_t Dat)
{
    ST7735S_SetAddressWindow(x, y, x + 1, y + 1);
    ST7735S_WriteData_16Bit(Dat);
    //Sbuf[x + y*W] = Color;
}

/**
 * 读TFT某一点颜色
 * 
 * */
uint16_t ST7735S_ReadPoint(uint16_t x, uint16_t y)
{
    uint16_t c = 0x00;
    ST7735S_SetXY(x, y);
    ST7735S_WriteData(c);
    return c;
}

void ST7735S_SetColor(uint16_t color)
{
    Color = color;
}

void ST7735S_DrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t Color)
{
    int dx,  // difference in x's
        dy,  // difference in y's
        dx2, // dx,dy * 2
        dy2,
        x_inc, // amount in pixel space to move during drawing
        y_inc, // amount in pixel space to move during drawing
        error, // the discriminant i.e. error i.e. decision variable
        index; // used for looping

    ST7735S_SetXY(x0, y0);
    dx = x1 - x0; //计算x距离
    dy = y1 - y0; //计算y距离

    if (dx >= 0)
    {
        x_inc = 1;
    }
    else
    {
        x_inc = -1;
        dx = -dx;
    }

    if (dy >= 0)
    {
        y_inc = 1;
    }
    else
    {
        y_inc = -1;
        dy = -dy;
    }

    dx2 = dx << 1;
    dy2 = dy << 1;

    if (dx > dy) //x距离大于y距离，那么每个x轴上只有一个点，每个y轴上有若干个点
    {            //且线的点数等于x距离，以x轴递增画点
        // initialize error term
        error = dy2 - dx;

        // draw the line
        for (index = 0; index <= dx; index++) //要画的点数不会超过x距离
        {
            //画点
            ST7735S_DrawPoint(x0, y0, Color);

            // test if error has overflowed
            if (error >= 0) //是否需要增加y坐标值
            {
                error -= dx2;

                // move to next line
                y0 += y_inc; //增加y坐标值
            }                // end if error overflowed

            // adjust the error term
            error += dy2;

            // move to the next pixel
            x0 += x_inc; //x坐标值每次画点后都递增1
        }                // end for
    }                    // end if |slope| <= 1
    else                 //y轴大于x轴，则每个y轴上只有一个点，x轴若干个点
    {                    //以y轴为递增画点
        // initialize error term
        error = dx2 - dy;

        // draw the line
        for (index = 0; index <= dy; index++)
        {
            // set the pixel
            ST7735S_DrawPoint(x0, y0, Color);

            // test if error overflowed
            if (error >= 0)
            {
                error -= dy2;

                // move to next line
                x0 += x_inc;
            } // end if error overflowed

            // adjust the error term
            error += dx2;

            // move to the next pixel
            y0 += y_inc;
        } // end for
    }     // end else |slope| > 1
}

void ST7735S_DrawRect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t c)
{
    uint16_t m, n;
    ST7735S_SetAddressWindow(x1, y1, x2, y2);
    ST7735S_WriteCommand(0x2C);
    for (m = x1; m < x2; m++)
    {
        for (n = y1; n < y2; n++)
        {
            ST7735S_WriteData_16Bit(c);
        }
    }
}

void ST7735S_FillScreen(uint16_t color)
{
    uint16_t m, n;
    ST7735S_SetAddressWindow(0, 0, ST7735S_WIDTH - 1, ST7735S_HEIGHT - 1);
    ST7735S_WriteCommand(0x2C);
    for (m = 0; m < ST7735S_WIDTH; m++)
    {
        for (n = 0; n < ST7735S_HEIGHT; n++)
        {
            ST7735S_WriteData_16Bit(color);
        }
    }
}

void ST7735S_ClearScreen(uint16_t color)
{
    ST7735S_FillScreen(color);
}

#define font font1608

void ST7735S_DrawFont_GBK16(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s)
{
    uint8_t i, j;
    uint16_t k, x0;
    x0 = x;
    while (*s)
    {
        if ((*s) < 128)
        {
            k = *s;
            if (k == 13)
            {
                x = x0;
                y += 16;
            }
            else
            {
                if (k > 32)
                    k -= 32;
                else
                    k = 0;
                for (i = 0; i < 16; i++)
                {
                    for (j = 0; j < 8; j++)
                    {
                        if (font[k * 16 + i] & (0x80 >> j))
                            ST7735S_DrawPoint(x + j, y + i, fc);
                        else
                        {
                            if (fc != bc)
                                ST7735S_DrawPoint(x + j, y + i, bc);
                        }
                    }
                }
                x += 8;
            }
            s++;
        }
    }
}


void ST7735S_DrawNum(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint16_t num)
{
    uint16_t i, j, k, c;
    for(i = 0; i < 32; i++)
    {
        for(j = 0; j < 4; j++)
        {
            c=*(sz16 + num*16*4+i*4+j);
            for(k = 0; k < 8; k++)
            {
                if(c&(0x80>>k))
                    ST7735S_DrawPoint(x+j*8+k,y+i,fc);
                else
                {
                    if(fc != bc)
                    {
                        ST7735S_DrawPoint(x+j*8+k,y+i,bc);
                    }
                }
                
            }
        }
    }
}

#if 0
void ST7735S_DrawString(char *str, uint16_t x, uint16_t y)
{
    uint16_t r = 0;
    while(*str)
    {
        ST7735S_DrawChar(*str++, x + r, y);
        r += 8;
    }
}

void ST7735S_DrawNum(long n, uint16_t x, uint16_t y)
{
    char buf[12];
    ST7735S_DrawString(buf, x, y);
}

void ST7735S_DrawImage(const uint8_t *p)
{
    int i, j, k;
    uint8_t imgMSB, imgLSB;
    ST7735S_Clear(0);
    ST7735S_SetPos(0, 0, 128, 160);
    for(i = 0; i < 128 * 160; i++)
    {
        imgLSB = *(p + i * 2);
        imgMSB = *(p + i * 2 + 1);
        ST7735S_WriteData_16Bit(imgMSB << 8 | imgLSB);
    }
        
}
#endif
